/*@internal*/
名域 ts {
    /** This is the cache of module/typedirectives resolution that can be retained across program */
    导出 接口 解析缓存_ {
        开始记录文件包括改变解析(): 无值;
        完成记录文件包括改变解析(): 路径_[] | 未定;

        解析模块名称组(模块名称组: 文字[], 包含文件: 文字, 重复使用名称: 文字[] | 未定): 解析的模块名称_[];

        使文件解析失效(文件路径: 路径_): 无值;
        删除文件的解析(文件路径: 路径_): 无值;
        创建具有实现解析(强制所有文件失效?: 真假): 有已失效的解析_;

        启动每个目录的缓存解析(): 无值;
        完成每个目录的缓存解析(): 无值;

        清除(): 无值;
    }

    接口 解析包括失败查找位置组_ {
        是无效的?: 真假;
        引用数量?: 数字;
    }

    接口 解析包括解析文件名称_ {
        解析的模块目录路径: 文字 | 未定;
    }

    接口 解析模块包括失败的查找位置_ 扩展 ts.解析模块包括失败的查找位置_, 解析包括失败查找位置组_ {
    }

    导出 接口 解析缓存主机_ 扩展 模块解析主机_ {
        转为路径(文件名: 文字): 路径_;
        获取规范文件名称: 获取规范文件名称_;
        获取编译设置(): 编译选项_;
        正在无效决议(): 无值;
        获取缓存目录结构主机(): 缓存目录文件主机_ | 未定;
        项目名称?: 文字;
        获取全局缓存?(): 文字 | 未定;
        写日志(s: 文字): 无值;
        最大文件迭代失败数量?: 数字;
        获取当前程序(): 程序_;
    }


    导出 常量 失败迭代的最大文件数 = 256;

    类型 获取解析包括解析文件名称_<T 扩展 解析包括失败查找位置组_ = 解析包括失败查找位置组_, R 扩展 解析包括解析文件名称_ = 解析包括解析文件名称_> = (解析的: T) => R;

    导出 函数 创建解析缓存(解析主机: 解析缓存主机_, 模块依赖: 词典_<文字>, 解析模块时记录更改: 真假): 解析缓存_ {
        变量 具有已更改的未解析导入的文件: 路径_[] | 未定;
        变量 文件组包括失败的解析组: 词典_<为真> | 未定;
        变量 文件包含无效的非相对未解析导入: 词典_<只读数组_<文字>> | 未定;
        变量 所有文件都无效 = 为假;

        常量 获取当前目录 = 记忆(() => 解析主机.获取当前目录!());

        // The resolvedModuleNames and resolvedTypeReferenceDirectives are the cache of resolutions per 文件.
        // The key in the map is source 文件's 路径.
        // The values are 词典_ of resolutions with key being 名称 lookedup.
        常量 解析的模块名称组 = 创建词典<词典_<解析模块包括失败的查找位置_>>();
        常量 按目录解析的模块名组 = 创建词典<词典_<解析模块包括失败的查找位置_>>();
        常量 非关系模块名称缓存 = 创建词典<预处理模块名称缓存_>();
        常量 模块解析缓存 = 创建模块解析缓存包括词典(
            按目录解析的模块名组,
            非关系模块名称缓存,
            获取当前目录(),
            解析主机.获取规范文件名称
        );

        常量 自定义失败查找路径 = 创建词典<数字>();

        返回 {
            开始记录文件包括改变解析,
            完成记录文件包括改变解析,
            启动每个目录的缓存解析,
            完成每个目录的缓存解析,
            解析模块名称组,
            删除文件的解析,
            使文件解析失效,
            创建具有实现解析,
            清除
        };

        函数 获取解析的模块(解析的: 解析模块包括失败的查找位置_) {
            返回 解析的.模块目录路径!;
        }

        函数 清除() {
            自定义失败查找路径.清除();
            解析的模块名称组.清除();
            所有文件都无效 = 为假;
            // perDirectoryResolvedModuleNames and perDirectoryResolvedTypeReferenceDirectives could be non empty if there was exception during program update
            // (between startCachingPerDirectoryResolution and finishCachingPerDirectoryResolution)
            启动每个目录的缓存解析();
        }

        函数 开始记录文件包括改变解析() {
            具有已更改的未解析导入的文件 = [];
        }

        函数 完成记录文件包括改变解析() {
            常量 收集的 = 具有已更改的未解析导入的文件;
            具有已更改的未解析导入的文件 = 未定;
            返回 收集的;
        }

        函数 是文件包含无效的非相对未解析导入(路径: 路径_): 真假 {
            如果 (!文件包含无效的非相对未解析导入) {
                返回 为假;
            }

            // Invalidated if 文件 has unresolved imports
            常量 值 = 文件包含无效的非相对未解析导入.获取(路径);
            返回 !!值 && !!值.长度;
        }

        函数 创建具有实现解析(强制所有文件无效?: 真假): 有已失效的解析_ {
            如果 (所有文件都无效 || 强制所有文件无效) {
                // Any 文件 asked would have invalidated resolution
                文件组包括失败的解析组 = 未定;
                返回 返回真;
            }
            常量 收集的 = 文件组包括失败的解析组;
            文件组包括失败的解析组 = 未定;
            返回 路径 => (!!收集的 && 收集的.具有(路径)) ||
            是文件包含无效的非相对未解析导入(路径);
        }

        函数 启动每个目录的缓存解析() {
            按目录解析的模块名组.清除();
            非关系模块名称缓存.清除();
        }

        函数 完成每个目录的缓存解析() {
            所有文件都无效 = 为假;
            启动每个目录的缓存解析();
        }

        函数 解析模块名称(模块名称: 文字, 包含文件: 文字, 编译选项: 编译选项_, 主机: 模块解析主机_): 解析模块包括失败的查找位置_ {
            常量 主要结果 = ts.解析模块名称(模块名称, 包含文件, 编译选项, 主机, 模块依赖, 模块解析缓存 );
            // return 结果 immediately only if global cache support is not 启用 or if it is .ts, .tsx or .d.ts
            如果 (!解析主机.获取全局缓存) {
                返回 主要结果;
            }

            常量 全局缓存 = 解析主机.获取全局缓存();
            如果 (全局缓存 !== 未定 && !主要结果.模块目录路径) {
                // create different collection of failed lookup locations for second pass
                // if it will fail and we've already found something during the 首个 pass - we don't want to pollute its results
                常量 { 模块目录路径: 解析模块 } = 加载模块从全局缓存(模块名称, 解析主机.项目名称!, 编译选项, 主机, 全局缓存);
                如果 (解析模块) {
                    返回 { 模块目录路径: 解析模块 };
                }
            }

            // Default return the 结果 from the 首个 pass
            返回 主要结果;
        }

        函数 解析名称包括绑定缓存<T 扩展 解析包括失败查找位置组_, R 扩展 解析包括解析文件名称_>(
            名称组: 文字[],
            包含文件: 文字,
            缓存: 词典_<词典_<T>>,
            每个目录缓存: 词典_<词典_<T>>,
            加载器: (名称: 文字, 包含文件: 文字, 选项组: 编译选项_, 主机: 模块解析主机_) => T,
            获取解析包括解析文件名称: 获取解析包括解析文件名称_<T, R>,
            重复使用的名称: 文字[] | 未定,
            日志更改: 真假): R[] {

            常量 路径 = 解析主机.转为路径(包含文件);
            常量 解析的在文件中 = 缓存.获取(路径) || 缓存.设置(路径, 创建词典()).获取(路径);
            常量 目录路径 = 获取目录路径(路径);
            变量 按目录解析 = 每个目录缓存.获取(目录路径);
            如果 (!按目录解析) {
                按目录解析 = 创建词典();
                每个目录缓存.设置(目录路径, 按目录解析);
            }

            常量 解析模块组: R[] = [];
            常量 编译选项组 = 解析主机.获取编译设置();

            常量 看见名称在文件 = 创建词典<为真>();
            循环 (常量 名称 属于 名称组) {
                变量 解析的 = 解析的在文件中!.获取(名称);
                // Resolution is valid if it is present and not invalidated
                如果 (!看见名称在文件.具有(名称) &&
                    所有文件都无效 || !解析的 || 解析的.是无效的) {
                    常量 现有的解析 = 解析的;
                    常量 目录中的解析 = 按目录解析.获取(名称);
                    如果 (目录中的解析) {
                        解析的 = 目录中的解析;
                    }
                    否则 {
                        解析的 = 加载器(名称, 包含文件, 编译选项组, 解析主机);
                        按目录解析.设置(名称, 解析的);
                    }
                    解析的在文件中!.设置(名称, 解析的);

                    如果 (日志更改 && 具有已更改的未解析导入的文件 && !解析是相等的(现有的解析!, 解析的)) {
                        具有已更改的未解析导入的文件.压入(路径);
                        // reset log changes to avoid recording the same 文件 multiple times
                        日志更改 = 为假;
                    }
                }
                调试_.断言(解析的 !== 未定 && !解析的.是无效的);
                看见名称在文件.设置(名称, 为真);
                解析模块组.压入(获取解析包括解析文件名称(解析的));
            }

            // Stop watching and remove the unused 名称
            解析的在文件中!.循环执行((_, 名称) => {
                如果 (!看见名称在文件.具有(名称) && !包含(重复使用的名称, 名称)) {
                    解析的在文件中!.删除(名称);
                }
            });

            返回 解析模块组;

            函数 解析是相等的(旧解析: T, 新解析: T): 真假 {
                如果 (旧解析 === 新解析) {
                    返回 为真;
                }
                如果 (!旧解析 || !新解析 || 旧解析.是无效的) {
                    返回 为假;
                }
                常量 旧结果 = 获取解析包括解析文件名称(旧解析);
                常量 新结果 = 获取解析包括解析文件名称(新解析);
                如果 (旧结果 === 新结果) {
                    返回 为真;
                }
                如果 (!旧结果 || !新结果) {
                    返回 为假;
                }
                返回 旧结果.解析的模块目录路径 === 新结果.解析的模块目录路径;
            }
        }


        函数 解析模块名称组(模块名称: 文字[], 包含文件: 文字, 重复使用名称: 文字[] | 未定): 解析的模块名称_[] {
            返回 解析名称包括绑定缓存(
                模块名称,
                包含文件,
                解析的模块名称组,
                按目录解析的模块名组,
                解析模块名称,
                获取解析的模块,
                重复使用名称,
                解析模块时记录更改
            );
        }

        函数 删除文件从缓存的解析(缓存: 词典_<词典_<解析包括失败查找位置组_>>, 文件路径: 路径_) {
            // Deleted 文件, stop watching failed lookups for all the resolutions in the 文件
            常量 解析组 = 缓存.获取(文件路径);
            如果 (解析组) {
                缓存.删除(文件路径);
            }
        }

        函数 删除文件的解析(文件路径: 路径_) {
            删除文件从缓存的解析(解析的模块名称组, 文件路径);
        }

        函数 无效解析缓存<T 扩展 解析包括失败查找位置组_, R 扩展 解析包括解析文件名称_>(
            缓存: 词典_<词典_<T>>,
            是无效的解析: (解析的: T, 获取解析包括解析文件名称: 获取解析包括解析文件名称_<T, R>) => 真假,
            获取解析包括解析文件名称: 获取解析包括解析文件名称_<T, R>
        ) {
            常量 看到的 = 创建词典<词典_<为真>>();
            缓存.循环执行((解析组, 包含文件路径) => {
                常量 目录路径 = 获取目录路径(包含文件路径);
                变量 看到在目录 = 看到的.获取(目录路径);
                如果 (!看到在目录) {
                    看到在目录 = 创建词典<为真>();
                    看到的.设置(目录路径, 看到在目录);
                }
                解析组.循环执行((解析的, 名称) => {
                    如果 (看到在目录!.具有(名称)) {
                        返回;
                    }
                    看到在目录!.设置(名称, 为真);
                    如果 (!解析的.是无效的 && 是无效的解析(解析的, 获取解析包括解析文件名称)) {
                        // Mark the 文件 as needing re-evaluation of module resolution instead of using it blindly.
                        解析的.是无效的 = 为真;
                        (文件组包括失败的解析组 || (文件组包括失败的解析组 = 创建词典<为真>())).设置(包含文件路径, 为真);
                    }
                });
            });
        }

        函数 具有达到解析迭代限制() {
            常量 最大大小 = 解析主机.最大文件迭代失败数量 || 失败迭代的最大文件数;
            返回 解析的模块名称组.大小 > 最大大小;
        }

        函数 使解析无效(
            是无效的解析: (解析的: 解析包括失败查找位置组_, 获取解析包括解析文件名称: 获取解析包括解析文件名称_) => 真假,
        ) {
            // If more than maxNumberOfFilesToIterateForInvalidation present,
            // just invalidated all files and recalculate the resolutions for files instead
            如果 (具有达到解析迭代限制()) {
                所有文件都无效 = 为真;
                返回;
            }
            无效解析缓存(解析的模块名称组, 是无效的解析, 获取解析的模块);
        }

        函数 使文件解析失效(文件路径: 路径_) {
            删除文件的解析(文件路径);
            使解析无效((解析的, 获取解析包括解析文件名称) => {
                    常量 结果 = 获取解析包括解析文件名称(解析的);
                    返回 结果 && 解析主机.转为路径(结果.解析的模块目录路径!) === 文件路径;
                }
            );
        }

    }
}
